package com.zwg.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.zwg.tingshu.album.AlbumFeignClient;
import com.zwg.tingshu.common.constant.RedisConstant;
import com.zwg.tingshu.common.constant.RocketMqConstant;
import com.zwg.tingshu.common.service.RocketMqService;
import com.zwg.tingshu.common.util.AuthContextHolder;
import com.zwg.tingshu.model.user.*;
import com.zwg.tingshu.user.mapper.*;
import com.zwg.tingshu.user.mapper.*;
import com.zwg.tingshu.user.service.UserInfoService;
import com.zwg.tingshu.user.strategy.ItemTypeStrategy;
import com.zwg.tingshu.user.strategy.StrategyFactory;
import com.zwg.tingshu.vo.user.UserInfoVo;
import com.zwg.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zwg.tingshu.model.user.UserInfo;
import com.zwg.tingshu.model.user.UserPaidAlbum;
import com.zwg.tingshu.model.user.UserPaidTrack;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	@Autowired
	private UserInfoMapper userInfoMapper;
	@Autowired
	private WxMaService wxMaService;
	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private RocketMqService rocketMqService;

	@Autowired
	private UserPaidAlbumMapper userPaidAlbumMapper;
	@Autowired
	private UserPaidTrackMapper userPaidTrackMapper;
	@Autowired
	private AlbumFeignClient albumFeignClient;
	@Autowired
	private VipServiceConfigMapper vipServiceConfigMapper;
	@Autowired
	private UserVipServiceMapper userVipServiceMapper;
	@Autowired
	private StrategyFactory strategyFactory;

	/**
	 * 更新Vip到期失效状态
	 *
	 * @return
	 */
	@Override
	public void updateVipExpireStatus() {
		//1.已经过期会员
		LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(UserInfo::getIsVip, "1");
		queryWrapper.lt(UserInfo::getVipExpireTime, DateUtil.beginOfDay(new Date()));
		List<UserInfo> list = this.list(queryWrapper);
		//2.批量更新
		if (CollectionUtil.isNotEmpty(list)) {
			List<UserInfo> collect = list.stream().map(userInfo -> {
				UserInfo userInfo1 = new UserInfo();
				userInfo1.setIsVip(0);
				userInfo1.setId(userInfo.getId());
				return userInfo1;
			}).collect(Collectors.toList());
			this.updateBatchById(collect);
		}
	}

	/**
	 * 处理用户购买记录（虚拟物品发货）
	 *
	 * @param userPaidRecordVo 购买记录VO
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) {
		//从策略工厂中获取对应的策略对象
		ItemTypeStrategy strategy = strategyFactory.getStrategy(userPaidRecordVo.getItemType());
		//执行策略对象的任务
		strategy.savePaidRecord(userPaidRecordVo);
	}


	/**
	 * 根据用户ID+专辑ID查询已购声音集合
	 *
	 * @param userId 用户ID
	 * @param albumId 专辑ID
	 * @return
	 */
	@Override
	public List<Long> getUserPaidTrackIdList(Long userId, Long albumId) {
		//1.根据用户ID+专辑ID查询已购声音集合
		LambdaQueryWrapper<UserPaidTrack> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(UserPaidTrack::getUserId, userId);
		queryWrapper.eq(UserPaidTrack::getAlbumId, albumId);
		List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(queryWrapper);
		if (CollectionUtil.isNotEmpty(userPaidTrackList)) {
			//2.获取已购声音ID集合
			List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
			return userPaidTrackIdList;
		}
		return null;
	}


	/**
	 * 验证当前用户是否购买过专辑
	 *
	 * @param albumId
	 * @return
	 */
	@Override
	public Boolean isPaidAlbum(Long albumId) {
		//1.获取当前用户ID
		Long userId = AuthContextHolder.getUserId();
		//2.构建查询条件：用户ID+专辑ID 查询专辑购买记录表
		LambdaQueryWrapper<UserPaidAlbum> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(UserPaidAlbum::getUserId, userId);
		queryWrapper.eq(UserPaidAlbum::getAlbumId, albumId);
		Long count = userPaidAlbumMapper.selectCount(queryWrapper);
		return count > 0;
	}

	/**
	 * 判断当前用户某一页中声音列表购买情况
	 *
	 * @param userId 用户ID
	 * @param albumId 专辑ID
	 * @param needChackTrackIdList 待检查购买情况声音列表
	 * @return data:{声音ID：购买结果} 结果：1（已购）0（未购买）
	 */
	@Override
	public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needChackTrackIdList) {
		//1.根据用户ID+专辑ID查询已购专辑表
		LambdaQueryWrapper<UserPaidAlbum> userPaidAlbumLambdaQueryWrapper = new LambdaQueryWrapper<>();
		userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getAlbumId, albumId);
		userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getUserId, userId);
		Long count = userPaidAlbumMapper.selectCount(userPaidAlbumLambdaQueryWrapper);
		if (count > 0) {
		//1.1 存在专辑购买记录-用户购买过该专辑，将待检查声音列表购买情况设置为：1
			Map<Long, Integer> mapResult = new HashMap<>();
			for (Long trackId : needChackTrackIdList) {
				mapResult.put(trackId, 1);
			}
			return mapResult;
		}
		//2. 不存在专辑购买记录-根据用户ID+声音列表查询已购声音表
		LambdaQueryWrapper<UserPaidTrack> userPaidTrackLambdaQueryWrapper = new LambdaQueryWrapper<>();
		userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getUserId, userId);
		userPaidTrackLambdaQueryWrapper.in(UserPaidTrack::getTrackId, needChackTrackIdList);
		//获取本页中已购买声音列表
		List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(userPaidTrackLambdaQueryWrapper);
		//2.1 不存在声音购买记录-将待检查声音列表购买情况设置为：0
		if (CollectionUtil.isEmpty(userPaidTrackList)) {
			Map<Long, Integer> mapResult = new HashMap<>();
			for (Long trackId : needChackTrackIdList) {
				mapResult.put(trackId, 0);
			}
			return mapResult;
		}
		//2.2 存在声音购买记录-循环判断待检查声音ID找出哪些是已购，哪些是未购买
		List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
		Map<Long, Integer> mapResult = new HashMap<>();
		for (Long needCheckTrackId : needChackTrackIdList) {
			//如果待检查声音ID包含在已购声音Id集合中（已购买）
			if (userPaidTrackIdList.contains(needCheckTrackId)) {
				mapResult.put(needCheckTrackId, 1);
			} else {
				//反之则未购买声音
				mapResult.put(needCheckTrackId, 0);
			}
		}
		return mapResult;
	}

	/**
	 * 小程序端提交临时凭据code，登录（调用微信接口获取微信账号唯一标识：openId）
	 *
	 * @param code 临时凭据
	 * @return 对象，登录登录成功后：token
	 */
	@Override
	public Map<String, String> wxLogin(String code) {
		try {
			//1.根据入参提交临时票据，调用微信获取微信账户唯一标识接口，得到微信账户openId
			WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
			if (sessionInfo != null) {
				//2.根据微信唯一标识查询用户记录
				String wxOpenId = sessionInfo.getOpenid();
				//2.1 如果查询为空-将微信OpenId跟听书项目中用户关联（新增用户记录中存储微信账户唯一标识）
				LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
				queryWrapper.eq(UserInfo::getWxOpenId, wxOpenId);
				UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
				if (userInfo == null) {
					//2.2 为首次登录用户构建用户对象，保存用户记录
					userInfo = new UserInfo();
					userInfo.setWxOpenId(wxOpenId);
					userInfo.setNickname("听友" + IdUtil.getSnowflakeNextId());
					userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
					userInfo.setIsVip(0);
					userInfoMapper.insert(userInfo);
					//2.3 发送RocketMq异步消息，通知账户微服务新增账户记录
					rocketMqService.sendAsync(RocketMqConstant.QUEUE_USER_REGISTER,RocketMqConstant.QUEUE_USER_REGISTER,userInfo.getId().toString());
				}
				//3.基于用户记录生成Token 将用户令牌存入Redis Key:前缀+token Value:用户信息UserInfoVo
				String token = IdUtil.fastUUID();
				String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
				//排除掉用户隐私数据
				UserInfoVo userInfoVo = BeanUtil.copyProperties(userInfo, UserInfoVo.class);
				redisTemplate.opsForValue().set(loginKey, userInfoVo, RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);
				//4.将用户token封装结果返回
				Map<String, String> mapResult = new HashMap<>();
				mapResult.put("token", token);
				return mapResult;
			}
			return null;
		} catch (Exception e) {
			log.error("[用户服务]微信登录异常：{}", e);
			throw new RuntimeException(e);
		}
	}

	/**
	 * 查询用户基本信息
	 *
	 * @param userId
	 * @return
	 */
	@Override
	public UserInfoVo getUserInfo(Long userId) {
		//1.根据主键ID查询用户对象
		UserInfo userInfo = userInfoMapper.selectById(userId);
		//2.将用户PO对象转为VO对象
		return BeanUtil.copyProperties(userInfo, UserInfoVo.class);
	}

	/**
	 * 修改用户基本信息（限定只能修改账户昵称、头像）
	 *
	 * @param userId
	 * @param userInfoVo
	 */
	@Override
	public void updateUser(Long userId, UserInfoVo userInfoVo) {
		UserInfo userInfo = new UserInfo();
		userInfo.setId(userId);
		userInfo.setNickname(userInfoVo.getNickname());
		userInfo.setAvatarUrl(userInfoVo.getAvatarUrl());
		userInfoMapper.updateById(userInfo);
	}

	/**
	 * 根据用户ID获取用户（主播）基本信息
	 *
	 * @param userId
	 * @return
	 */
	@Override
	public UserInfoVo getUserInfoVoById(Long userId) {
		//2.根据用户ID查询用户记录UserInfo
		UserInfo userInfo = userInfoMapper.selectById(userId);
		//3.转为UserInfoVo返回
		return BeanUtil.copyProperties(userInfo, UserInfoVo.class);
	}
}
